/**
 * Copyright 2008-2009. Chongqing Communications Industry Services Co.,Ltd Information Technology Branch. All rights
 * reserved. <a>http://www.cqcis.com</a>
 */
package com.cqcis.uip.base.framework.utils;

import java.lang.reflect.InvocationHandler;
import java.lang.reflect.Method;
import java.lang.reflect.Proxy;
import java.util.concurrent.ThreadPoolExecutor;

import com.cqcis.uip.base.framework.UIPServiceException;

/**
 * 动态异步方法执行，代理. 
 * 方法的真正执行被委托到另外的线程中进行
 * 
 * LogServiceThreadPoolExecutor.getLogExecutor(0, 0, 0, 
    				serviceContext, "DynamicAsyncMethodProxy-" + serviceContext.getRegisteredService().getName());
 * 
 * @author huangmy
 * @date   2008-11-25
 */
public class DynamicAsyncMethodProxyUtil {
	private final static Object NULL_OBJ = new Object(); // NULL
	
	/**
	 * 创建线程执行代理
	 * 
	 * @param target   
	 * @param proxyInterface 如果为null，则用target实现的接口进行代理
	 * @param tpe
	 * @return
	 */
    public final static Object create(final Object target, Class<?> proxyInterface, final ThreadPoolExecutor tpe) {
    	if (target == null || tpe == null) {
    		throw new UIPServiceException("target and threadpoolexecutor can't be null.");
    	}
    	
    	InvocationHandler h = new InvocationHandler() {
    		public Object invoke(Object proxy, final Method method, final Object[] args)
    				throws Throwable {
    			final ConcurrentTaskQueue<Object> syncQueue = new ConcurrentTaskQueue<Object>();
    			
    			tpe.execute(new Runnable() {
    				public void run() {
    					Object ro = Void.TYPE;
    					
    					try {
    					    ro = method.invoke(target, args);
    					} catch (Throwable t) {
    						ro = t;
    					} finally {
    						ro = (ro != null) ? ro : NULL_OBJ;
    						syncQueue.offer(ro);
    					}
    				}
    			});
    			
    			Object ro = syncQueue.poll();
    			if (ro != null && (ro instanceof Throwable)) {
    				throw (Throwable)ro;
    			}
    			
    			if (NULL_OBJ == ro) {
    				return null;
    			}
    			    			
    			return ro;
    		}
    	};
    	
    	Class<?>[] intfs = null;
    	if (proxyInterface != null) {
    		intfs = new Class<?>[]{proxyInterface};
    	} else {
    		intfs = target.getClass().getInterfaces();
    	}
    	    	    	
    	return Proxy.newProxyInstance(target.getClass().getClassLoader(), intfs, h);
    }
}
